home *** CD-ROM | disk | FTP | other *** search
/ Point Programming 1 / PPROG1.ISO / pascal / swag / textfile.swg / 0019_Reading Backwards.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-08-27  |  7.3 KB  |  292 lines

  1. {
  2. >  Can anyone help me figure out how I can move a Text File position
  3. >  Pointer backwards instead of forwards?
  4. }
  5.  
  6. {$R-,S-,I-}
  7.  
  8. {
  9.  Turbo Pascal 4.0 Unit to read Text Files backwards.
  10.  
  11.  See TESTRB.PAS For a test and demonstration Program. Routines here
  12.  are used in a manner very similar to normal Text File read routines
  13.  except that the "reset" positions to the end of the File, and each
  14.  subsequent "readln" returns the prior line in the File Until the
  15.  beginning of the File is reached.
  16.  
  17.  Each String returned by ReadLnBack is in normal forward order.
  18.  
  19.  One quirk will occur if an attempt is made to read from Files With
  20.  lines longer than 255 Characters. In this Case ReadLnBack will return
  21.  the _last_ 255 Characters of each such line rather than the first. This
  22.  is in keeping With the backwards nature of the Unit, however.
  23.  
  24.  Hope someone finds a use For this!
  25.  
  26.  Written 6/7/88, Kim Kokkonen, TurboPower Software.
  27.  Released to the public domain.
  28. }
  29.  
  30. Unit RB;
  31.   {-Read Text Files backwards}
  32.  
  33. Interface
  34.  
  35. Type
  36.   BackText = File;                {We use the UserData area in the unTyped File
  37.  
  38. Procedure AssignBack(Var F : BackText; Fname : String);
  39.   {-Assign a backwards File to a File Variable}
  40.  
  41. Procedure ResetBack(Var F : BackText; BufSize : Word);
  42.   {-Reset a backwards File, allocating buffer space (128 Bytes or greater)}
  43.  
  44. Procedure ReadLnBack(Var F : BackText; Var S : String);
  45.   {-Read next line from end of backwards File}
  46.  
  47. Procedure CloseBack(Var F : BackText);
  48.   {-Close backwards File, releasing buffer}
  49.  
  50. Function BoF(Var F : BackText) : Boolean;
  51.   {-Return True when F is positioned at beginning of File}
  52.  
  53. Function BackResult : Word;
  54.   {-Return I/O status code from operation}
  55.  
  56.   {======================================================================}
  57.  
  58. Implementation
  59.  
  60. Const
  61.   LF = #10;
  62.  
  63. Type
  64.   BufferArray = Array[1..65521] of Char;
  65.   BackRec =                       {Same as Dos.FileRec, With UserData filled in
  66.     Record
  67.       Handle : Word;
  68.       Mode : Word;
  69.       RecSize : Word;
  70.       Private : Array[1..26] of Byte;
  71.       Fpos : LongInt;             {Current File position}
  72.       BufP : ^BufferArray;        {Pointer to Text buffer}
  73.       Bpos : Word;                {Current position Within buffer}
  74.       Bcnt : Word;                {Count of Characters in buffer}
  75.       Bsize : Word;               {Size of Text buffer, 0 if none}
  76.       UserData : Array[15..16] of Byte; {Remaining UserData}
  77.       Name : Array[0..79] of Char;
  78.     end;
  79.  
  80. Var
  81.   BResult : Word;                 {Internal IoResult}
  82.  
  83.   Procedure AssignBack(Var F : BackText; Fname : String);
  84.     {-Assign a backwards File to a File Variable}
  85.   begin
  86.     if BResult = 0 then begin
  87.       Assign(File(F), Fname);
  88.       BResult := IoResult;
  89.     end;
  90.   end;
  91.  
  92.   Procedure ResetBack(Var F : BackText; BufSize : Word);
  93.     {-Reset a backwards File, allocating buffer}
  94.   Var
  95.     BR : BackRec Absolute F;
  96.   begin
  97.     if BResult = 0 then
  98.       With BR do begin
  99.         {Open File}
  100.         Reset(File(F), 1);
  101.         BResult := IoResult;
  102.         if BResult <> 0 then
  103.           Exit;
  104.  
  105.         {Seek to end}
  106.         Fpos := FileSize(File(F));
  107.         Seek(File(F), Fpos);
  108.         BResult := IoResult;
  109.         if BResult <> 0 then
  110.           Exit;
  111.  
  112.         {Allocate buffer}
  113.         if BufSize < 128 then
  114.           BufSize := 128;
  115.         if MaxAvail < BufSize then begin
  116.           BResult := 203;
  117.           Exit;
  118.         end;
  119.         GetMem(BufP, BufSize);
  120.         Bsize := BufSize;
  121.         Bcnt := 0;
  122.         Bpos := 0;
  123.       end;
  124.   end;
  125.  
  126.   Function BoF(Var F : BackText) : Boolean;
  127.     {-Return True when F is at beginning of File}
  128.   Var
  129.     BR : BackRec Absolute F;
  130.   begin
  131.     With BR do
  132.       BoF := (Fpos = 0) and (Bpos = 0);
  133.   end;
  134.  
  135.   Function GetCh(Var F : BackText) : Char;
  136.     {-Return next Character from end of File}
  137.   Var
  138.     BR : BackRec Absolute F;
  139.     Bread : Word;
  140.   begin
  141.     With BR do begin
  142.       if Bpos = 0 then
  143.         {Buffer used up}
  144.         if Fpos > 0 then begin
  145.           {Unread File remains, first reposition File Pointer}
  146.           Bread := Bsize;
  147.           Dec(Fpos, Bread);
  148.           if Fpos < 0 then begin
  149.             {Reduce the number of Characters to read}
  150.             Inc(Bread, Fpos);
  151.             Fpos := 0;
  152.           end;
  153.           Seek(File(F), Fpos);
  154.           BResult := IoResult;
  155.           if BResult <> 0 then
  156.             Exit;
  157.  
  158.           {Refill buffer}
  159.           BlockRead(File(F), BufP^, Bread, Bcnt);
  160.           BResult := IoResult;
  161.           if BResult <> 0 then
  162.             Exit;
  163.  
  164.           {Remove ^Z's from end of buffer}
  165.           While (Bcnt > 0) and (BufP^[Bcnt] = ^Z) do
  166.             Dec(Bcnt);
  167.           Bpos := Bcnt;
  168.           if Bpos = 0 then begin
  169.             {At beginning of File}
  170.             GetCh := LF;
  171.             Exit;
  172.           end;
  173.  
  174.         end else begin
  175.           {At beginning of File}
  176.           GetCh := LF;
  177.           Exit;
  178.         end;
  179.  
  180.       {Return next Character}
  181.       GetCh := BufP^[Bpos];
  182.       Dec(Bpos);
  183.     end;
  184.   end;
  185.  
  186.   Procedure ReadLnBack(Var F : BackText; Var S : String);
  187.     {-Read next line from end of backwards File}
  188.   Var
  189.     Slen : Byte Absolute S;
  190.     Tpos : Word;
  191.     Tch : Char;
  192.     T : String;
  193.   begin
  194.     Slen := 0;
  195.     if (BResult = 0) and not BoF(F) then begin
  196.       {Build String from end backwards}
  197.       Tpos := 256;
  198.       Repeat
  199.         Tch := GetCh(F);
  200.         if BResult <> 0 then
  201.           Exit;
  202.         if Tpos > 1 then begin
  203.           Dec(Tpos);
  204.           T[Tpos] := Tch;
  205.         end;
  206.         {Note that GetCh arranges to return LF at beginning of File}
  207.       Until Tch = LF;
  208.       {Transfer to result String}
  209.       Slen := 255-Tpos;
  210.       if Slen > 0 then
  211.         Move(T[Tpos+1], S[1], Slen);
  212.       {Skip over (presumed) CR}
  213.       Tch := GetCh(F);
  214.     end;
  215.   end;
  216.  
  217.   Procedure CloseBack(Var F : BackText);
  218.     {-Close backwards File, releasing buffer}
  219.   Var
  220.     BR : BackRec Absolute F;
  221.   begin
  222.     if BResult = 0 then
  223.       With BR do begin
  224.         Close(File(F));
  225.         BResult := IoResult;
  226.         if BResult <> 0 then
  227.           Exit;
  228.         FreeMem(BufP, Bsize);
  229.       end;
  230.   end;
  231.  
  232.   Function BackResult : Word;
  233.     {-Return I/O status code from operation}
  234.   begin
  235.     BackResult := BResult;
  236.     BResult := 0;
  237.   end;
  238.  
  239. begin
  240.   BResult := 0;
  241. end.
  242.  
  243.  
  244. And now, the little test Program TESTRB.PAS that demonstrates how to use the
  245.  Unit:
  246.  
  247. {
  248.  Demonstration Program For RB.PAS.
  249.  Takes one command line parameter, the name of a Text File to read backwards.
  250.  Reads File one line at a time backwards and Writes the result to StdOut.
  251.  
  252.  See RB.PAS For further details.
  253.  
  254.  Written 6/7/88, Kim Kokkonen, TurboPower Software.
  255.  Released to the public domain.
  256. }
  257.  
  258. Program Test;
  259.   {-Demonstrate RB Unit}
  260.  
  261. Uses
  262.   RB;
  263.  
  264. Var
  265.   F : BackText;
  266.   S : String;
  267.  
  268.   Procedure CheckError(Result : Word);
  269.   begin
  270.     if Result <> 0 then begin
  271.       WriteLn('RB error ', Result);
  272.       Halt;
  273.     end;
  274.   end;
  275.  
  276. begin
  277.   if ParamCount = 0 then
  278.     AssignBack(F, 'RB.PAS')
  279.   else
  280.     AssignBack(F, ParamStr(1));
  281.   CheckError(BackResult);
  282.   ResetBack(F, 1024);
  283.   CheckError(BackResult);
  284.   While not BoF(F) do begin
  285.     ReadLnBack(F, S);
  286.     CheckError(BackResult);
  287.     WriteLn(S);
  288.   end;
  289.   CloseBack(F);
  290.   CheckError(BackResult);
  291. end.
  292.